import * as THREE from 'three'
import { Zone } from "./zone"
import { Scene } from "./scene"
import { Camera } from "./camera"
import { Light } from "./light"
import { Controls } from "./controls"
import { Clock } from "./clock"
import { Stats } from "./stats"

import { merge } from "lodash"
/**
 * 构造器和控制器
 */
export class Park {
  #defaultOptions = {
    
  }
  
  constructor(el, options) {
    if (!(el instanceof HTMLElement)) {
      throw new Error("第一个参数必须是一个HTMLElement对象");
    }

    this.el = el;
    this.options = merge({}, this.#defaultOptions, options);

    this.init()

    this.scene = new Scene(this)
    this.camera = new Camera(this)
    this.light = new Light(this)
    this.controls = new Controls(this)
    this.clock = new Clock(this)
    this.stats = new Stats(this)
    this.drawGridHelper()
    this.zone = new Zone(this)

    this.resize()
    window.addEventListener('resize', this.resize.bind(this), false)
  }

  init() {
    let container = new THREE.WebGLRenderer({ antialias: true })
    container.shadowMap.enabled = true
    container.setPixelRatio(window.devicePixelRatio)
    container.setSize(window.innerWidth, window.innerHeight)
    this.el.appendChild(container.domElement)
    this.container = container;
  }

  drawGridHelper() {
    let gridHelper = new THREE.GridHelper(400, 160, new THREE.Color(0x555555), new THREE.Color(0x333333))
    this.scene.add(gridHelper)
  }

  render() {
    this.container.render(this.scene, this.camera)
    this.controls.update(this.clock.getDelta())
    this.stats.update()

    this.animationFrame = requestAnimationFrame(proxy(this.render, this));
  }

  resize() {
    if (this.scene) {
      this.camera.aspect = window.innerWidth / window.innerHeight
      this.camera.updateProjectionMatrix()
      this.container.setSize(window.innerWidth, window.innerHeight)
    }
  }
}




/**
 * 数组的constructor
 * @const
 * @type {Array}
 */
var ARRAY = Array;

/**
 * 数组的prototype
 * @const
 * @type {Object}
 */
var ARRAY_PROTOTYPE = ARRAY.prototype;
/**
 * 代理函数
 * @param fn
 * @param context
 * @returns {*}
 */
function proxy(fn, context) {
  var args;

  if (!isFunction(fn)) {
    return undefined;
  }

  args = ARRAY_PROTOTYPE.slice.call(arguments, 2);

  return function () {
    return fn.apply(context || this, args.concat(ARRAY_PROTOTYPE.slice.call(arguments)));
  };
}

/**
 * 判断变量是否是函数
 * @param {*} obj 要判断的变量
 * @returns {boolean}
 */
function isFunction(obj) {
  return typeof obj === "function";
}